package myerror

import (
	"fmt"
	"reflect"
	"strings"
)

type ErrorCode int

type CustomError struct {
	Code        ErrorCode
	Message     string
	OriginError error
	Metadata    map[string]any
}

func (e *CustomError) Error() string {
	return e.Message
}

func (e *CustomError) Unwrap() error {
	return e.OriginError
}

func CollectErrorDetails(err error) []map[string]interface{} {
	var details []map[string]interface{}

	for current := err; current != nil; {
		// 初始化当前错误信息
		entry := make(map[string]interface{})

		// 处理 CustomError
		if customErr, ok := current.(*CustomError); ok {
			entry["type"] = "CustomError"
			entry["code"] = customErr.Code
			entry["message"] = customErr.Message
			entry["metadata"] = customErr.Metadata

			// 移动到下层错误
			current = customErr.OriginError
		} else {
			// 处理标准错误
			entry["type"] = reflect.TypeOf(current).String()
			entry["message"] = current.Error()

			// 尝试解包标准错误
			if unwrappable, ok := current.(interface{ Unwrap() error }); ok {
				current = unwrappable.Unwrap()
			} else {
				current = nil
			}
		}

		details = append(details, entry)
	}

	return details
}
func FormatErrorLog(err error) string {
	details := CollectErrorDetails(err)

	var builder strings.Builder
	builder.WriteString("\n===== ERROR TRACE =====\n")

	for i, entry := range details {
		builder.WriteString(fmt.Sprintf("Layer %d [%s]\n", i+1, entry["type"]))
		builder.WriteString(fmt.Sprintf("Message: %s\n", entry["message"]))

		if code, ok := entry["code"]; ok {
			builder.WriteString(fmt.Sprintf("Code: %d\n", code))
		}

		if metadata, ok := entry["metadata"]; ok {
			builder.WriteString(fmt.Sprintf("Metadata: %+v\n", metadata))
		}

		builder.WriteString("----------------------\n")
	}

	builder.WriteString("=======================")
	return builder.String()
}

// database
const (
	// common
	Unknown ErrorCode = 1000

	// DB
	DefaultFailure ErrorCode = 2000

	ForeignKeyViolated ErrorCode = 2001
	RecordNotFound     ErrorCode = 2002

	// service
	ServiceDefaultFailure ErrorCode = 3000
	// handler
	InvalidRequest ErrorCode = 4000
)
